/// <license>
/// This software and are provided as-is and without  warranty. 
/// This is  free  software,  as long  as you  clearly  display
/// the original author and his company for at least  1  second
/// on the attached display. If you need a commercial   license 
/// in which you do not have these restrictions, please contact
/// us via our website.
/// 
/// Author: Mario Di Vece
/// Unosquare S.A. de C.V. Copyright (c) 2013
/// url: http://www.unosquare.com
/// </license>

namespace Unosquare.Labs.Drivers.Vizic
{
    using System;
    using Microsoft.SPOT;
    using Unosquare.Labs.Utils;

    /// <summary>
    /// An object representing a scene, perfroming input, clearing the screen, drawing objects, and a UI
    /// </summary>
    public abstract class VizicSceneBase
    {
        protected bool IsPendingStop = false;

        public int MsPerFrame { get; protected set; }
        public bool IsLagging { get; protected set; }
        public long Elapsed { get; protected set; }
        public bool LimitFramerate { get; set; }

        public VizicColor BackgroundColor { get; set; }

        public VizicSceneObjectBase[] SceneObjects
        {
            get;
            protected set;
        }

        public VizicSmartGpu LCD
        {
            get;
            protected set;
        }

        public VizicSceneBase(VizicSmartGpu lcd)
        {
            this.MsPerFrame = 48; // 36 kind of works, 72 is okay too
            this.LCD = lcd;
            this.BackgroundColor = VizicColor.Black;
            this.LimitFramerate = true;
        }

        protected void InvalidateObjects()
        {
            // draw the objects
            if (SceneObjects == null || SceneObjects.Length == 0)
                return;

            // draw objects
            foreach (var obj in this.SceneObjects)
                if (obj != null)
                    obj.Invalidate();
        }

        protected abstract void UpdateObjects();

        protected abstract void DrawUI();

        protected void DrawObjects()
        {
            if (SceneObjects == null || SceneObjects.Length == 0)
                return;

            // draw objects
            foreach (var obj in this.SceneObjects)
                if (obj != null)
                    obj.Draw();
        }

        public void Start()
        {
            this.IsPendingStop = false;
            var thread = new System.Threading.Thread(FrameLoop);
            thread.Start();
        }

        private void FrameLoop()
        {
            this.LCD.BackgroundColor = this.BackgroundColor;
            this.LCD.ClearScreen();

            this.Elapsed = 0;
            this.IsLagging = false;

            while (IsPendingStop == false)
            {
                var frameStartTime = DateTime.Now;
                this.InvalidateObjects();
                this.UpdateObjects();
                this.DrawObjects();
                this.DrawUI();

                this.Elapsed = DateTime.Now.Subtract(frameStartTime).TotalMilliseconds();
                if (this.Elapsed >= MsPerFrame)
                {
                    this.IsLagging = true;
                    continue;
                }

                this.IsLagging = false;
                if (LimitFramerate)
                {
                    System.Threading.Thread.Sleep((int)(MsPerFrame - this.Elapsed));
                    this.Elapsed = MsPerFrame;
                }
            }

            IsPendingStop = false;
        }

        public void Stop()
        {
            if (IsPendingStop)
                return;

            IsPendingStop = true;
        }

    }
}
